package com.my.network.nio;

import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

/**
 * @author mars
 * @date 2025-03-26 14:31
 */
@Slf4j
public class NioServerSocketServer {
    public static void main(String[] args) {
        try (
                var serverSocketChannel = ServerSocketChannel.open();
        ) {
            // 非阻塞模式
            serverSocketChannel.configureBlocking(false);
            serverSocketChannel.bind(new InetSocketAddress(9500));
            // 创建 Selector 并注册 ACCEPT 事件
            var selector = Selector.open();
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
            while (true) {
                selector.select(); // 阻塞直到有事件发生
                Set<SelectionKey> keys = selector.selectedKeys();
                Iterator<SelectionKey> it = keys.iterator();

                while (it.hasNext()) {
                    SelectionKey key = it.next();
                    it.remove();
                    if (key.isAcceptable()) {
                        handleAccept(selector, key); // 处理新连接
                    } else if (key.isReadable()) {
                        handleRead(key);   // 处理读事件
                    }
                }
            }
        } catch (IOException e) {
            log.error("error", e);
        }
    }

    private static void handleAccept(Selector selector, SelectionKey key) throws IOException {
        ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();
        SocketChannel clientChannel = serverChannel.accept();
        clientChannel.configureBlocking(false);
        clientChannel.register(selector, SelectionKey.OP_READ); // 注册读事件
        log.info("客户端连接: {}", clientChannel.getRemoteAddress());
    }

    private static void handleRead(SelectionKey key) throws IOException {
        SocketChannel channel = (SocketChannel) key.channel();
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        int bytesRead = channel.read(buffer);

        if (bytesRead == -1) { // 客户端关闭连接
            channel.close();
            log.info("客户端断开连接");
            return;
        }

        buffer.flip();
        byte[] data = new byte[buffer.remaining()];
        buffer.get(data);
        log.info("收到数据: {}", new String(data));
        // 回写数据（可选）
        channel.write(ByteBuffer.wrap("Server ACK".getBytes()));
    }
}
